# 探究植物生长受光照、水分和温度三种因素的影响情况，光照、水分、温度都分为低和高两种水平
# 植物的生长情况由植物生长高度和叶子数量来度量
import multiprocessing
import random
from pprint import pprint

init_state = {
    'height': 0,
    'leaf_num': 0
}
params = {
    'sunlight': [1, 3],
    'water': ['low', 'mid', 'high'],
    'temperature': [1, 10],
    'soil': [3, 20],
}


def dfs(x, k, n, values, index, capacity):
    if x == k:
        s = 0
        for key in capacity.keys():
            capacity[key].append(index[s])
            s = s + 1
        return capacity

    if len(values[x]) != 2 or type(values[x][0]) == str:
        for i in range(n):
            index[x] = values[x][i]
            capacity = dfs(x + 1, k, n, values, index, capacity)
    else:
        for i in range(n):
            index[x] = values[x][0] + (values[x][1] - values[x][0]) / (n - 1) * i
            capacity = dfs(x + 1, k, n, values, index, capacity)

    return capacity


def is_numeric(character):
    return character.isnumeric()


# k 为因子数，n 为因子水平数，
# param为字典，表示因子水平的上限和下限/表示因子的不同水平，字典的项数=k。即对于param中每一项的数组：要么包含两项表示下限和上限要么包含n项表示该因子的不同水平。
def getCapacity(k, n, param):
    assert len(param) == k, '参数中的因子数与k不相等'
    assert n >= 2, '因子水平数至少为2'
    capacity = {}
    for item in param.items():
        assert type(item[1]) == list, '参数中的因子水平必须为数组的形式'

        values = item[1]
        for i in range(len(values) - 1):
            assert type(values[i]) == type(values[i + 1]), '同一个因子水平的类型必须相同'
        if len(item[1]) != 2:
            assert len(item[1]) == n, '参数中自定义的因子数与n不同'
        else:
            if is_numeric(f'{item[1][0]}') and is_numeric(f'{item[1][1]}'):
                assert item[1][1] >= item[1][0], f'参数中的 {item[0]} 不符合要求, 低水平必须小于高水平'

        capacity.update(dict([(item[0], [])]))

    index = []
    for i in range(len(capacity)):
        index.append(0)
    capacity = dfs(0, k, n, list(param.values()), index, capacity)

    return capacity


def run():
    capacity = getCapacity(k=4, n=3, param=params)
    print(capacity)


if __name__ == "__main__":
    multiprocessing.freeze_support()
    run()
